package models

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
	"time"

	"github.com/beego/beego/v2/client/orm"
	"github.com/beego/beego/v2/server/web/context"
	"github.com/dgrijalva/jwt-go"
)

type Classmates struct {
	Id        int     `orm:"column(id);auto"`
	Name      string  `orm:"column(name);size(45);null"`
	Sn        string  `orm:"column(sn);size(45);null"`
	Sex       string  `orm:"column(sex);size(5);null"`
	Tel       string  `orm:"column(tel);size(45);null"`
	Email     string  `orm:"column(email);size(45);null"`
	Grade     int     `orm:"column(grade);null" description:"年级"`
	Classname string  `orm:"column(classname);size(45);null"`
	Ip1       string  `orm:"column(ip1);size(45);null"`
	Comments  string  `orm:"column(comments);size(105);null"`
	Status    string  `orm:"column(status);size(50);null"`
	Xueji     string  `orm:"column(xueji);size(50);null"`
	Ip2       string  `orm:"column(ip2);size(45);null"`
	Ip3       string  `orm:"column(ip3);size(45);null"`
	Pswd      string  `orm:"column(pswd);size(45);null"`
	Gitee     string  `orm:"column(gitee);size(85);null"`
	Account   float64 `orm:"column(account);null;digits(20);decimals(2)" description:"账号"`
}

func (t *Classmates) TableName() string {
	return "classmates"
}

func init() {
	orm.RegisterModel(new(Classmates))
}

// AddClassmates insert a new Classmates into database and returns
// last inserted Id on success.
func AddClassmates(m *Classmates) (id int64, err error) {
	o := orm.NewOrm()
	id, err = o.Insert(m)
	return
}

// GetClassmatesById retrieves Classmates by Id. Returns error if
// Id doesn't exist
func GetClassmatesById(id int) (v *Classmates, err error) {
	o := orm.NewOrm()
	v = &Classmates{Id: id}
	if err = o.Read(v); err == nil {
		return v, nil
	}
	return nil, err
}

// GetAllClassmates retrieves all Classmates matches certain condition. Returns empty list if
// no records exist
func GetAllClassmates(query map[string]string, fields []string, sortby []string, order []string,
	offset int64, limit int64) (ml []interface{}, err error) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(Classmates))
	// query k=v
	for k, v := range query {
		// rewrite dot-notation to Object__Attribute
		k = strings.Replace(k, ".", "__", -1)
		if strings.Contains(k, "isnull") {
			qs = qs.Filter(k, (v == "true" || v == "1"))
		} else {
			qs = qs.Filter(k, v)
		}
	}
	// order by:
	var sortFields []string
	if len(sortby) != 0 {
		if len(sortby) == len(order) {
			// 1) for each sort field, there is an associated order
			for i, v := range sortby {
				orderby := ""
				if order[i] == "desc" {
					orderby = "-" + v
				} else if order[i] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
			qs = qs.OrderBy(sortFields...)
		} else if len(sortby) != len(order) && len(order) == 1 {
			// 2) there is exactly one order, all the sorted fields will be sorted by this order
			for _, v := range sortby {
				orderby := ""
				if order[0] == "desc" {
					orderby = "-" + v
				} else if order[0] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
		} else if len(sortby) != len(order) && len(order) != 1 {
			return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
		}
	} else {
		if len(order) != 0 {
			return nil, errors.New("Error: unused 'order' fields")
		}
	}

	var l []Classmates
	qs = qs.OrderBy(sortFields...)
	if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
		if len(fields) == 0 {
			for _, v := range l {
				ml = append(ml, v)
			}
		} else {
			// trim unused fields
			for _, v := range l {
				m := make(map[string]interface{})
				val := reflect.ValueOf(v)
				for _, fname := range fields {
					m[fname] = val.FieldByName(fname).Interface()
				}
				ml = append(ml, m)
			}
		}
		return ml, nil
	}
	return nil, err
}

// UpdateClassmates updates Classmates by Id and returns error if
// the record to be updated doesn't exist
func UpdateClassmatesById(m *Classmates) (err error) {
	o := orm.NewOrm()
	v := Classmates{Id: m.Id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Update(m); err == nil {
			fmt.Println("Number of records updated in database:", num)
		}
	}
	return
}

// DeleteClassmates deletes Classmates by Id and returns error if
// the record to be deleted doesn't exist
func DeleteClassmates(id int) (code int, err error) {
	o := orm.NewOrm()
	v := Classmates{Id: id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		if _, err = o.Delete(&Classmates{Id: id}); err == nil {
			return 1000, nil
		} else {
			return 1001, fmt.Errorf("删除失败，原因是:" + err.Error())
		}
	} else {
		return 1001, fmt.Errorf("用户不存在")
	}
}

// 模型   映射了数据库的模型。并负责处理具体的事情
func Login(sn, pswd string) (result *Classmates, err error) {
	o := orm.NewOrm()
	result = new(Classmates)
	o.QueryTable("classmates").Filter("sn", sn).One(result)
	if result.Id <= 0 {
		return nil, fmt.Errorf("用户不存在")
	}
	if result.Pswd == pswd {
		return result, nil
	}
	return nil, fmt.Errorf("密码不正确")
}

func Register() {
	var user = new(Classmates)
	user.Name = "zhangsan"
	user.Sex = "nv"
	user.Classname = "一班"
	user.Email = "jyy@qq.com"

	o := orm.NewOrm()
	o.Insert(user)

	// 添加

	// 修改

	// 删除

	o.Raw("delete from classmates where name=?", "zhangsan").Exec()
	// insert
}

func Updatepswd(userid int, old, newpswd string) bool {
	o := orm.NewOrm()
	var user Classmates
	user.Id = userid
	o.Read(&user)

	if user.Pswd != old {
		return false
	}
	user.Pswd = newpswd
	o.Update(&user)
	return true
}

type Export struct {
	Code    int
	Message string
	Data    interface{}
}

func ZhuanZhang(fromID, receiveID int, money float64) bool {

	o := orm.NewOrm()
	//1. 获取  转账人  的账户，减少 money 数字
	var fromer Classmates
	fromer.Id = fromID
	err := o.Read(&fromer)
	if err != nil {
		return false
	}
	fromer.Account -= float64(money)

	// 2. 获取 接收人  的账户  增加money是数字
	var receiver Classmates
	receiver.Id = receiveID
	err = o.Read(&receiver)
	if err != nil {
		return false
	}
	receiver.Account += float64(money)
	_, err = o.Update(&fromer)
	if err != nil {
		return false
	}
	_, err = o.Update(&receiver)
	if err != nil {
		return false
	}
	return true

}

// 定义密钥，用于签名和验证JWT
var jwtKey = []byte("my_secret_key")

// Claims是一个结构体，用于存储JWT中的声明信息
type Claims struct {
	UserID int `json:"userid"`
	jwt.StandardClaims
}

// GenerateJWT生成一个新的JWT令牌
func GenerateJWT(userid int, youxiaoqi time.Duration) (string, error) {
	// 设置过期时间，这里设置为1小时后过期
	expirationTime := time.Now().Add(youxiaoqi * time.Hour)

	// 创建Claims结构体实例，设置用户名和过期时间等信息
	claims := &Claims{
		UserID: userid,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expirationTime.Unix(),
		},
	}

	// 使用HS256算法创建一个新的JWT令牌
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 使用密钥对令牌进行签名
	signedToken, err := token.SignedString(jwtKey)
	if err != nil {
		return "", err
	}

	return signedToken, nil
}

// ValidateJWT验证给定的JWT令牌是否有效
func ValidateJWT(tokenString string) (*Claims, bool) {
	// 解析JWT令牌
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtKey, nil
	})

	// 检查解析过程中是否有错误
	if err != nil {
		return nil, false
	}

	// 验证令牌是否有效且未过期
	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		return claims, true
	}

	return nil, false
}

// 过滤器 身份验证的问题
func FilterUser(ctx *context.Context) {

	Token := ctx.Input.Header("Token")
	jwt, _ := ValidateJWT(Token)
	ctx.Input.SetData("jwt", jwt)
}
